home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / cl_main.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  40.9 KB  |  1,845 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // cl_main.c  -- client main loop
  21.  
  22. #include "client.h"
  23.  
  24. cvar_t    *freelook;
  25.  
  26. cvar_t    *adr0;
  27. cvar_t    *adr1;
  28. cvar_t    *adr2;
  29. cvar_t    *adr3;
  30. cvar_t    *adr4;
  31. cvar_t    *adr5;
  32. cvar_t    *adr6;
  33. cvar_t    *adr7;
  34. cvar_t    *adr8;
  35.  
  36. cvar_t    *cl_stereo_separation;
  37. cvar_t    *cl_stereo;
  38.  
  39. cvar_t    *rcon_client_password;
  40. cvar_t    *rcon_address;
  41.  
  42. cvar_t    *cl_noskins;
  43. cvar_t    *cl_autoskins;
  44. cvar_t    *cl_footsteps;
  45. cvar_t    *cl_timeout;
  46. cvar_t    *cl_predict;
  47. //cvar_t    *cl_minfps;
  48. cvar_t    *cl_maxfps;
  49. cvar_t    *cl_gun;
  50.  
  51. cvar_t    *cl_add_particles;
  52. cvar_t    *cl_add_lights;
  53. cvar_t    *cl_add_entities;
  54. cvar_t    *cl_add_blend;
  55.  
  56. cvar_t    *cl_shownet;
  57. cvar_t    *cl_showmiss;
  58. cvar_t    *cl_showclamp;
  59.  
  60. cvar_t    *cl_paused;
  61. cvar_t    *cl_timedemo;
  62.  
  63. cvar_t    *lookspring;
  64. cvar_t    *lookstrafe;
  65. cvar_t    *sensitivity;
  66.  
  67. cvar_t    *m_pitch;
  68. cvar_t    *m_yaw;
  69. cvar_t    *m_forward;
  70. cvar_t    *m_side;
  71.  
  72. cvar_t    *cl_lightlevel;
  73.  
  74. //
  75. // userinfo
  76. //
  77. cvar_t    *info_password;
  78. cvar_t    *info_spectator;
  79. cvar_t    *name;
  80. cvar_t    *skin;
  81. cvar_t    *rate;
  82. cvar_t    *fov;
  83. cvar_t    *msg;
  84. cvar_t    *hand;
  85. cvar_t    *gender;
  86. cvar_t    *gender_auto;
  87.  
  88. cvar_t    *cl_vwep;
  89.  
  90. client_static_t    cls;
  91. client_state_t    cl;
  92.  
  93. centity_t        cl_entities[MAX_EDICTS];
  94.  
  95. entity_state_t    cl_parse_entities[MAX_PARSE_ENTITIES];
  96.  
  97. extern    cvar_t *allow_download;
  98. extern    cvar_t *allow_download_players;
  99. extern    cvar_t *allow_download_models;
  100. extern    cvar_t *allow_download_sounds;
  101. extern    cvar_t *allow_download_maps;
  102.  
  103. //======================================================================
  104.  
  105.  
  106. /*
  107. ====================
  108. CL_WriteDemoMessage
  109.  
  110. Dumps the current net message, prefixed by the length
  111. ====================
  112. */
  113. void CL_WriteDemoMessage (void)
  114. {
  115.     int        len, swlen;
  116.  
  117.     // the first eight bytes are just packet sequencing stuff
  118.     len = net_message.cursize-8;
  119.     swlen = LittleLong(len);
  120.     fwrite (&swlen, 4, 1, cls.demofile);
  121.     fwrite (net_message.data+8,    len, 1, cls.demofile);
  122. }
  123.  
  124.  
  125. /*
  126. ====================
  127. CL_Stop_f
  128.  
  129. stop recording a demo
  130. ====================
  131. */
  132. void CL_Stop_f (void)
  133. {
  134.     int        len;
  135.  
  136.     if (!cls.demorecording)
  137.     {
  138.         Com_Printf ("Not recording a demo.\n");
  139.         return;
  140.     }
  141.  
  142. // finish up
  143.     len = -1;
  144.     fwrite (&len, 4, 1, cls.demofile);
  145.     fclose (cls.demofile);
  146.     cls.demofile = NULL;
  147.     cls.demorecording = false;
  148.     Com_Printf ("Stopped demo.\n");
  149. }
  150.  
  151. /*
  152. ====================
  153. CL_Record_f
  154.  
  155. record <demoname>
  156.  
  157. Begins recording a demo from the current position
  158. ====================
  159. */
  160. void CL_Record_f (void)
  161. {
  162.     char    name[MAX_OSPATH];
  163.     char    buf_data[MAX_MSGLEN];
  164.     sizebuf_t    buf;
  165.     int        i;
  166.     int        len;
  167.     entity_state_t    *ent;
  168.     entity_state_t    nullstate;
  169.  
  170.     if (Cmd_Argc() != 2)
  171.     {
  172.         Com_Printf ("record <demoname>\n");
  173.         return;
  174.     }
  175.  
  176.     if (cls.demorecording)
  177.     {
  178.         Com_Printf ("Already recording.\n");
  179.         return;
  180.     }
  181.  
  182.     if (cls.state != ca_active)
  183.     {
  184.         Com_Printf ("You must be in a level to record.\n");
  185.         return;
  186.     }
  187.  
  188.     //
  189.     // open the demo file
  190.     //
  191.     Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
  192.  
  193.     Com_Printf ("recording to %s.\n", name);
  194.     FS_CreatePath (name);
  195.     cls.demofile = fopen (name, "wb");
  196.     if (!cls.demofile)
  197.     {
  198.         Com_Printf ("ERROR: couldn't open.\n");
  199.         return;
  200.     }
  201.     cls.demorecording = true;
  202.  
  203.     // don't start saving messages until a non-delta compressed message is received
  204.     cls.demowaiting = true;
  205.  
  206.     //
  207.     // write out messages to hold the startup information
  208.     //
  209.     SZ_Init (&buf, buf_data, sizeof(buf_data));
  210.  
  211.     // send the serverdata
  212.     MSG_WriteByte (&buf, svc_serverdata);
  213.     MSG_WriteLong (&buf, PROTOCOL_VERSION);
  214.     MSG_WriteLong (&buf, 0x10000 + cl.servercount);
  215.     MSG_WriteByte (&buf, 1);    // demos are always attract loops
  216.     MSG_WriteString (&buf, cl.gamedir);
  217.     MSG_WriteShort (&buf, cl.playernum);
  218.  
  219.     MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
  220.  
  221.     // configstrings
  222.     for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
  223.     {
  224.         if (cl.configstrings[i][0])
  225.         {
  226.             if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
  227.             {    // write it out
  228.                 len = LittleLong (buf.cursize);
  229.                 fwrite (&len, 4, 1, cls.demofile);
  230.                 fwrite (buf.data, buf.cursize, 1, cls.demofile);
  231.                 buf.cursize = 0;
  232.             }
  233.  
  234.             MSG_WriteByte (&buf, svc_configstring);
  235.             MSG_WriteShort (&buf, i);
  236.             MSG_WriteString (&buf, cl.configstrings[i]);
  237.         }
  238.  
  239.     }
  240.  
  241.     // baselines
  242.     memset (&nullstate, 0, sizeof(nullstate));
  243.     for (i=0; i<MAX_EDICTS ; i++)
  244.     {
  245.         ent = &cl_entities[i].baseline;
  246.         if (!ent->modelindex)
  247.             continue;
  248.  
  249.         if (buf.cursize + 64 > buf.maxsize)
  250.         {    // write it out
  251.             len = LittleLong (buf.cursize);
  252.             fwrite (&len, 4, 1, cls.demofile);
  253.             fwrite (buf.data, buf.cursize, 1, cls.demofile);
  254.             buf.cursize = 0;
  255.         }
  256.  
  257.         MSG_WriteByte (&buf, svc_spawnbaseline);        
  258.         MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
  259.     }
  260.  
  261.     MSG_WriteByte (&buf, svc_stufftext);
  262.     MSG_WriteString (&buf, "precache\n");
  263.  
  264.     // write it to the demo file
  265.  
  266.     len = LittleLong (buf.cursize);
  267.     fwrite (&len, 4, 1, cls.demofile);
  268.     fwrite (buf.data, buf.cursize, 1, cls.demofile);
  269.  
  270.     // the rest of the demo file will be individual frames
  271. }
  272.  
  273. //======================================================================
  274.  
  275. /*
  276. ===================
  277. Cmd_ForwardToServer
  278.  
  279. adds the current command line as a clc_stringcmd to the client message.
  280. things like godmode, noclip, etc, are commands directed to the server,
  281. so when they are typed in at the console, they will need to be forwarded.
  282. ===================
  283. */
  284. void Cmd_ForwardToServer (void)
  285. {
  286.     char    *cmd;
  287.  
  288.     cmd = Cmd_Argv(0);
  289.     if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
  290.     {
  291.         Com_Printf ("Unknown command \"%s\"\n", cmd);
  292.         return;
  293.     }
  294.  
  295.     MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  296.     SZ_Print (&cls.netchan.message, cmd);
  297.     if (Cmd_Argc() > 1)
  298.     {
  299.         SZ_Print (&cls.netchan.message, " ");
  300.         SZ_Print (&cls.netchan.message, Cmd_Args());
  301.     }
  302. }
  303.  
  304. void CL_Setenv_f( void )
  305. {
  306.     int argc = Cmd_Argc();
  307.  
  308.     if ( argc > 2 )
  309.     {
  310.         char buffer[1000];
  311.         int i;
  312.  
  313.         strcpy( buffer, Cmd_Argv(1) );
  314.         strcat( buffer, "=" );
  315.  
  316.         for ( i = 2; i < argc; i++ )
  317.         {
  318.             strcat( buffer, Cmd_Argv( i ) );
  319.             strcat( buffer, " " );
  320.         }
  321.  
  322.         putenv( buffer );
  323.     }
  324.     else if ( argc == 2 )
  325.     {
  326.         char *env = getenv( Cmd_Argv(1) );
  327.  
  328.         if ( env )
  329.         {
  330.             Com_Printf( "%s=%s\n", Cmd_Argv(1), env );
  331.         }
  332.         else
  333.         {
  334.             Com_Printf( "%s undefined\n", Cmd_Argv(1), env );
  335.         }
  336.     }
  337. }
  338.  
  339.  
  340. /*
  341. ==================
  342. CL_ForwardToServer_f
  343. ==================
  344. */
  345. void CL_ForwardToServer_f (void)
  346. {
  347.     if (cls.state != ca_connected && cls.state != ca_active)
  348.     {
  349.         Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
  350.         return;
  351.     }
  352.     
  353.     // don't forward the first argument
  354.     if (Cmd_Argc() > 1)
  355.     {
  356.         MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  357.         SZ_Print (&cls.netchan.message, Cmd_Args());
  358.     }
  359. }
  360.  
  361.  
  362. /*
  363. ==================
  364. CL_Pause_f
  365. ==================
  366. */
  367. void CL_Pause_f (void)
  368. {
  369.     // never pause in multiplayer
  370.     if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
  371.     {
  372.         Cvar_SetValue ("paused", 0);
  373.         return;
  374.     }
  375.  
  376.     Cvar_SetValue ("paused", !cl_paused->value);
  377. }
  378.  
  379. /*
  380. ==================
  381. CL_Quit_f
  382. ==================
  383. */
  384. void CL_Quit_f (void)
  385. {
  386.     CL_Disconnect ();
  387.     Com_Quit ();
  388. }
  389.  
  390. /*
  391. ================
  392. CL_Drop
  393.  
  394. Called after an ERR_DROP was thrown
  395. ================
  396. */
  397. void CL_Drop (void)
  398. {
  399.     if (cls.state == ca_uninitialized)
  400.         return;
  401.     if (cls.state == ca_disconnected)
  402.         return;
  403.  
  404.     CL_Disconnect ();
  405.  
  406.     // drop loading plaque unless this is the initial game start
  407.     if (cls.disable_servercount != -1)
  408.         SCR_EndLoadingPlaque ();    // get rid of loading plaque
  409. }
  410.  
  411.  
  412. /*
  413. =======================
  414. CL_SendConnectPacket
  415.  
  416. We have gotten a challenge from the server, so try and
  417. connect.
  418. ======================
  419. */
  420. void CL_SendConnectPacket (void)
  421. {
  422.     netadr_t    adr;
  423.     int        port;
  424.  
  425.     if (!NET_StringToAdr (cls.servername, &adr))
  426.     {
  427.         Com_Printf ("Bad server address\n");
  428.         cls.connect_time = 0;
  429.         return;
  430.     }
  431.     if (adr.port == 0)
  432.         adr.port = BigShort (PORT_SERVER);
  433.  
  434.     port = Cvar_VariableValue ("qport");
  435.     userinfo_modified = false;
  436.  
  437.     Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
  438.         PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
  439. }
  440.  
  441. /*
  442. =================
  443. CL_CheckForResend
  444.  
  445. Resend a connect message if the last one has timed out
  446. =================
  447. */
  448. void CL_CheckForResend (void)
  449. {
  450.     netadr_t    adr;
  451.  
  452.     // if the local server is running and we aren't
  453.     // then connect
  454.     if (cls.state == ca_disconnected && Com_ServerState() )
  455.     {
  456.         cls.state = ca_connecting;
  457.         strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
  458.         // we don't need a challenge on the localhost
  459.         CL_SendConnectPacket ();
  460.         return;
  461. //        cls.connect_time = -99999;    // CL_CheckForResend() will fire immediately
  462.     }
  463.  
  464.     // resend if we haven't gotten a reply yet
  465.     if (cls.state != ca_connecting)
  466.         return;
  467.  
  468.     if (cls.realtime - cls.connect_time < 3000)
  469.         return;
  470.  
  471.     if (!NET_StringToAdr (cls.servername, &adr))
  472.     {
  473.         Com_Printf ("Bad server address\n");
  474.         cls.state = ca_disconnected;
  475.         return;
  476.     }
  477.     if (adr.port == 0)
  478.         adr.port = BigShort (PORT_SERVER);
  479.  
  480.     cls.connect_time = cls.realtime;    // for retransmit requests
  481.  
  482.     Com_Printf ("Connecting to %s...\n", cls.servername);
  483.  
  484.     Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
  485. }
  486.  
  487.  
  488. /*
  489. ================
  490. CL_Connect_f
  491.  
  492. ================
  493. */
  494. void CL_Connect_f (void)
  495. {
  496.     char    *server;
  497.  
  498.     if (Cmd_Argc() != 2)
  499.     {
  500.         Com_Printf ("usage: connect <server>\n");
  501.         return;    
  502.     }
  503.     
  504.     if (Com_ServerState ())
  505.     {    // if running a local server, kill it and reissue
  506.         SV_Shutdown (va("Server quit\n", msg), false);
  507.     }
  508.     else
  509.     {
  510.         CL_Disconnect ();
  511.     }
  512.  
  513.     server = Cmd_Argv (1);
  514.  
  515.     NET_Config (true);        // allow remote
  516.  
  517.     CL_Disconnect ();
  518.  
  519.     cls.state = ca_connecting;
  520.     strncpy (cls.servername, server, sizeof(cls.servername)-1);
  521.     cls.connect_time = -99999;    // CL_CheckForResend() will fire immediately
  522. }
  523.  
  524.  
  525. /*
  526. =====================
  527. CL_Rcon_f
  528.  
  529.   Send the rest of the command line over as
  530.   an unconnected command.
  531. =====================
  532. */
  533. void CL_Rcon_f (void)
  534. {
  535.     char    message[1024];
  536.     int        i;
  537.     netadr_t    to;
  538.  
  539.     if (!rcon_client_password->string)
  540.     {
  541.         Com_Printf ("You must set 'rcon_password' before\n"
  542.                     "issuing an rcon command.\n");
  543.         return;
  544.     }
  545.  
  546.     message[0] = (char)255;
  547.     message[1] = (char)255;
  548.     message[2] = (char)255;
  549.     message[3] = (char)255;
  550.     message[4] = 0;
  551.  
  552.     NET_Config (true);        // allow remote
  553.  
  554.     strcat (message, "rcon ");
  555.  
  556.     strcat (message, rcon_client_password->string);
  557.     strcat (message, " ");
  558.  
  559.     for (i=1 ; i<Cmd_Argc() ; i++)
  560.     {
  561.         strcat (message, Cmd_Argv(i));
  562.         strcat (message, " ");
  563.     }
  564.  
  565.     if (cls.state >= ca_connected)
  566.         to = cls.netchan.remote_address;
  567.     else
  568.     {
  569.         if (!strlen(rcon_address->string))
  570.         {
  571.             Com_Printf ("You must either be connected,\n"
  572.                         "or set the 'rcon_address' cvar\n"
  573.                         "to issue rcon commands\n");
  574.  
  575.             return;
  576.         }
  577.         NET_StringToAdr (rcon_address->string, &to);
  578.         if (to.port == 0)
  579.             to.port = BigShort (PORT_SERVER);
  580.     }
  581.     
  582.     NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
  583. }
  584.  
  585.  
  586. /*
  587. =====================
  588. CL_ClearState
  589.  
  590. =====================
  591. */
  592. void CL_ClearState (void)
  593. {
  594.     S_StopAllSounds ();
  595.     CL_ClearEffects ();
  596.     CL_ClearTEnts ();
  597.  
  598. // wipe the entire cl structure
  599.     memset (&cl, 0, sizeof(cl));
  600.     memset (&cl_entities, 0, sizeof(cl_entities));
  601.  
  602.     SZ_Clear (&cls.netchan.message);
  603.  
  604. }
  605.  
  606. /*
  607. =====================
  608. CL_Disconnect
  609.  
  610. Goes from a connected state to full screen console state
  611. Sends a disconnect message to the server
  612. This is also called on Com_Error, so it shouldn't cause any errors
  613. =====================
  614. */
  615. void CL_Disconnect (void)
  616. {
  617.     byte    final[32];
  618.  
  619.     if (cls.state == ca_disconnected)
  620.         return;
  621.  
  622.     if (cl_timedemo && cl_timedemo->value)
  623.     {
  624.         int    time;
  625.         
  626.         time = Sys_Milliseconds () - cl.timedemo_start;
  627.         if (time > 0)
  628.             Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
  629.             time/1000.0, cl.timedemo_frames*1000.0 / time);
  630.     }
  631.  
  632.     VectorClear (cl.refdef.blend);
  633.     R_SetPalette(NULL);
  634.  
  635.     M_ForceMenuOff ();
  636.  
  637.     cls.connect_time = 0;
  638.  
  639.     SCR_StopCinematic ();
  640.  
  641.     if (cls.demorecording)
  642.         CL_Stop_f ();
  643.  
  644.     // send a disconnect message to the server
  645.     final[0] = clc_stringcmd;
  646.     strcpy ((char *)final+1, "disconnect");
  647.     Netchan_Transmit (&cls.netchan, strlen(final), final);
  648.     Netchan_Transmit (&cls.netchan, strlen(final), final);
  649.     Netchan_Transmit (&cls.netchan, strlen(final), final);
  650.  
  651.     CL_ClearState ();
  652.  
  653.     // stop download
  654.     if (cls.download) {
  655.         fclose(cls.download);
  656.         cls.download = NULL;
  657.     }
  658.  
  659.     cls.state = ca_disconnected;
  660. }
  661.  
  662. void CL_Disconnect_f (void)
  663. {
  664.     Com_Error (ERR_DROP, "Disconnected from server");
  665. }
  666.  
  667.  
  668. /*
  669. ====================
  670. CL_Packet_f
  671.  
  672. packet <destination> <contents>
  673.  
  674. Contents allows \n escape character
  675. ====================
  676. */
  677. void CL_Packet_f (void)
  678. {
  679.     char    send[2048];
  680.     int        i, l;
  681.     char    *in, *out;
  682.     netadr_t    adr;
  683.  
  684.     if (Cmd_Argc() != 3)
  685.     {
  686.         Com_Printf ("packet <destination> <contents>\n");
  687.         return;
  688.     }
  689.  
  690.     NET_Config (true);        // allow remote
  691.  
  692.     if (!NET_StringToAdr (Cmd_Argv(1), &adr))
  693.     {
  694.         Com_Printf ("Bad address\n");
  695.         return;
  696.     }
  697.     if (!adr.port)
  698.         adr.port = BigShort (PORT_SERVER);
  699.  
  700.     in = Cmd_Argv(2);
  701.     out = send+4;
  702.     send[0] = send[1] = send[2] = send[3] = (char)0xff;
  703.  
  704.     l = strlen (in);
  705.     for (i=0 ; i<l ; i++)
  706.     {
  707.         if (in[i] == '\\' && in[i+1] == 'n')
  708.         {
  709.             *out++ = '\n';
  710.             i++;
  711.         }
  712.         else
  713.             *out++ = in[i];
  714.     }
  715.     *out = 0;
  716.  
  717.     NET_SendPacket (NS_CLIENT, out-send, send, adr);
  718. }
  719.  
  720. /*
  721. =================
  722. CL_Changing_f
  723.  
  724. Just sent as a hint to the client that they should
  725. drop to full console
  726. =================
  727. */
  728. void CL_Changing_f (void)
  729. {
  730.     //ZOID
  731.     //if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
  732.     if (cls.download)
  733.         return;
  734.  
  735.     SCR_BeginLoadingPlaque ();
  736.     cls.state = ca_connected;    // not active anymore, but not disconnected
  737.     Com_Printf ("\nChanging map...\n");
  738. }
  739.  
  740.  
  741. /*
  742. =================
  743. CL_Reconnect_f
  744.  
  745. The server is changing levels
  746. =================
  747. */
  748. void CL_Reconnect_f (void)
  749. {
  750.     //ZOID
  751.     //if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
  752.     if (cls.download)
  753.         return;
  754.  
  755.     S_StopAllSounds ();
  756.     if (cls.state == ca_connected) {
  757.         Com_Printf ("reconnecting...\n");
  758.         cls.state = ca_connected;
  759.         MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
  760.         MSG_WriteString (&cls.netchan.message, "new");        
  761.         return;
  762.     }
  763.  
  764.     if (*cls.servername) {
  765.         if (cls.state >= ca_connected) {
  766.             CL_Disconnect();
  767.             cls.connect_time = cls.realtime - 1500;
  768.         } else
  769.             cls.connect_time = -99999; // fire immediately
  770.  
  771.         cls.state = ca_connecting;
  772.         Com_Printf ("reconnecting...\n");
  773.     }
  774. }
  775.  
  776. /*
  777. =================
  778. CL_ParseStatusMessage
  779.  
  780. Handle a reply from a ping
  781. =================
  782. */
  783. void CL_ParseStatusMessage (void)
  784. {
  785.     char    *s;
  786.  
  787.     s = MSG_ReadString(&net_message);
  788.  
  789.     Com_Printf ("%s\n", s);
  790.     M_AddToServerList (net_from, s);
  791. }
  792.  
  793.  
  794. /*
  795. =================
  796. CL_PingServers_f
  797. =================
  798. */
  799. void CL_PingServers_f (void)
  800. {
  801.     int            i;
  802.     netadr_t    adr;
  803.     char        name[32];
  804.     char        *adrstring;
  805.     cvar_t        *noudp;
  806.     cvar_t        *noipx;
  807.  
  808.     NET_Config (true);        // allow remote
  809.  
  810.     // send a broadcast packet
  811.     Com_Printf ("pinging broadcast...\n");
  812.  
  813.     noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
  814.     if (!noudp->value)
  815.     {
  816.         adr.type = NA_BROADCAST;
  817.         adr.port = BigShort(PORT_SERVER);
  818.         Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
  819.     }
  820.  
  821.     noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
  822.     if (!noipx->value)
  823.     {
  824.         adr.type = NA_BROADCAST_IPX;
  825.         adr.port = BigShort(PORT_SERVER);
  826.         Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
  827.     }
  828.  
  829.     // send a packet to each address book entry
  830.     for (i=0 ; i<16 ; i++)
  831.     {
  832.         Com_sprintf (name, sizeof(name), "adr%i", i);
  833.         adrstring = Cvar_VariableString (name);
  834.         if (!adrstring || !adrstring[0])
  835.             continue;
  836.  
  837.         Com_Printf ("pinging %s...\n", adrstring);
  838.         if (!NET_StringToAdr (adrstring, &adr))
  839.         {
  840.             Com_Printf ("Bad address: %s\n", adrstring);
  841.             continue;
  842.         }
  843.         if (!adr.port)
  844.             adr.port = BigShort(PORT_SERVER);
  845.         Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
  846.     }
  847. }
  848.  
  849.  
  850. /*
  851. =================
  852. CL_Skins_f
  853.  
  854. Load or download any custom player skins and models
  855. =================
  856. */
  857. void CL_Skins_f (void)
  858. {
  859.     int        i;
  860.  
  861.     for (i=0 ; i<MAX_CLIENTS ; i++)
  862.     {
  863.         if (!cl.configstrings[CS_PLAYERSKINS+i][0])
  864.             continue;
  865.         Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]); 
  866.         SCR_UpdateScreen ();
  867.         Sys_SendKeyEvents ();    // pump message loop
  868.         CL_ParseClientinfo (i);
  869.     }
  870. }
  871.  
  872.  
  873. /*
  874. =================
  875. CL_ConnectionlessPacket
  876.  
  877. Responses to broadcasts, etc
  878. =================
  879. */
  880. void CL_ConnectionlessPacket (void)
  881. {
  882.     char    *s;
  883.     char    *c;
  884.     
  885.     MSG_BeginReading (&net_message);
  886.     MSG_ReadLong (&net_message);    // skip the -1
  887.  
  888.     s = MSG_ReadStringLine (&net_message);
  889.  
  890.     Cmd_TokenizeString (s, false);
  891.  
  892.     c = Cmd_Argv(0);
  893.  
  894.     Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
  895.  
  896.     // server connection
  897.     if (!strcmp(c, "client_connect"))
  898.     {
  899.         if (cls.state == ca_connected)
  900.         {
  901.             Com_Printf ("Dup connect received.  Ignored.\n");
  902.             return;
  903.         }
  904.         Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
  905.         MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
  906.         MSG_WriteString (&cls.netchan.message, "new");    
  907.         cls.state = ca_connected;
  908.         return;
  909.     }
  910.  
  911.     // server responding to a status broadcast
  912.     if (!strcmp(c, "info"))
  913.     {
  914.         CL_ParseStatusMessage ();
  915.         return;
  916.     }
  917.  
  918.     // remote command from gui front end
  919.     if (!strcmp(c, "cmd"))
  920.     {
  921.         if (!NET_IsLocalAddress(net_from))
  922.         {
  923.             Com_Printf ("Command packet from remote host.  Ignored.\n");
  924.             return;
  925.         }
  926.         Sys_AppActivate ();
  927.         s = MSG_ReadString (&net_message);
  928.         Cbuf_AddText (s);
  929.         Cbuf_AddText ("\n");
  930.         return;
  931.     }
  932.     // print command from somewhere
  933.     if (!strcmp(c, "print"))
  934.     {
  935.         s = MSG_ReadString (&net_message);
  936.         Com_Printf ("%s", s);
  937.         return;
  938.     }
  939.  
  940.     // ping from somewhere
  941.     if (!strcmp(c, "ping"))
  942.     {
  943.         Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
  944.         return;
  945.     }
  946.  
  947.     // challenge from the server we are connecting to
  948.     if (!strcmp(c, "challenge"))
  949.     {
  950.         cls.challenge = atoi(Cmd_Argv(1));
  951.         CL_SendConnectPacket ();
  952.         return;
  953.     }
  954.  
  955.     // echo request from server
  956.     if (!strcmp(c, "echo"))
  957.     {
  958.         Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
  959.         return;
  960.     }
  961.  
  962.     Com_Printf ("Unknown command.\n");
  963. }
  964.  
  965.  
  966. /*
  967. =================
  968. CL_DumpPackets
  969.  
  970. A vain attempt to help bad TCP stacks that cause problems
  971. when they overflow
  972. =================
  973. */
  974. void CL_DumpPackets (void)
  975. {
  976.     while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
  977.     {
  978.         Com_Printf ("dumnping a packet\n");
  979.     }
  980. }
  981.  
  982. /*
  983. =================
  984. CL_ReadPackets
  985. =================
  986. */
  987. void CL_ReadPackets (void)
  988. {
  989.     while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
  990.     {
  991. //    Com_Printf ("packet\n");
  992.         //
  993.         // remote command packet
  994.         //
  995.         if (*(int *)net_message.data == -1)
  996.         {
  997.             CL_ConnectionlessPacket ();
  998.             continue;
  999.         }
  1000.  
  1001.         if (cls.state == ca_disconnected || cls.state == ca_connecting)
  1002.             continue;        // dump it if not connected
  1003.  
  1004.         if (net_message.cursize < 8)
  1005.         {
  1006.             Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
  1007.             continue;
  1008.         }
  1009.  
  1010.         //
  1011.         // packet from server
  1012.         //
  1013.         if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
  1014.         {
  1015.             Com_DPrintf ("%s:sequenced packet without connection\n"
  1016.                 ,NET_AdrToString(net_from));
  1017.             continue;
  1018.         }
  1019.         if (!Netchan_Process(&cls.netchan, &net_message))
  1020.             continue;        // wasn't accepted for some reason
  1021.         CL_ParseServerMessage ();
  1022.     }
  1023.  
  1024.     //
  1025.     // check timeout
  1026.     //
  1027.     if (cls.state >= ca_connected
  1028.      && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
  1029.     {
  1030.         if (++cl.timeoutcount > 5)    // timeoutcount saves debugger
  1031.         {
  1032.             Com_Printf ("\nServer connection timed out.\n");
  1033.             CL_Disconnect ();
  1034.             return;
  1035.         }
  1036.     }
  1037.     else
  1038.         cl.timeoutcount = 0;
  1039.     
  1040. }
  1041.  
  1042.  
  1043. //=============================================================================
  1044.  
  1045. /*
  1046. ==============
  1047. CL_FixUpGender_f
  1048. ==============
  1049. */
  1050. void CL_FixUpGender(void)
  1051. {
  1052.     char *p;
  1053.     char sk[80];
  1054.  
  1055.     if (gender_auto->value) {
  1056.  
  1057.         if (gender->modified) {
  1058.             // was set directly, don't override the user
  1059.             gender->modified = false;
  1060.             return;
  1061.         }
  1062.  
  1063.         strncpy(sk, skin->string, sizeof(sk) - 1);
  1064.         if ((p = strchr(sk, '/')) != NULL)
  1065.             *p = 0;
  1066.         if (Q_stricmp(sk, "male") == 0 || Q_stricmp(sk, "cyborg") == 0)
  1067.             Cvar_Set ("gender", "male");
  1068.         else if (Q_stricmp(sk, "female") == 0 || Q_stricmp(sk, "crackhor") == 0)
  1069.             Cvar_Set ("gender", "female");
  1070.         else
  1071.             Cvar_Set ("gender", "none");
  1072.         gender->modified = false;
  1073.     }
  1074. }
  1075.  
  1076. /*
  1077. ==============
  1078. CL_Userinfo_f
  1079. ==============
  1080. */
  1081. void CL_Userinfo_f (void)
  1082. {
  1083.     Com_Printf ("User info settings:\n");
  1084.     Info_Print (Cvar_Userinfo());
  1085. }
  1086.  
  1087. /*
  1088. =================
  1089. CL_Snd_Restart_f
  1090.  
  1091. Restart the sound subsystem so it can pick up
  1092. new parameters and flush all sounds
  1093. =================
  1094. */
  1095. void CL_Snd_Restart_f (void)
  1096. {
  1097.     S_Shutdown ();
  1098.     S_Init ();
  1099.     CL_RegisterSounds ();
  1100. }
  1101.  
  1102. int precache_check; // for autodownload of precache items
  1103. int precache_spawncount;
  1104. int precache_tex;
  1105. int precache_model_skin;
  1106.  
  1107. byte *precache_model; // used for skin checking in alias models
  1108.  
  1109. #define PLAYER_MULT 5
  1110.  
  1111. // ENV_CNT is map load, ENV_CNT+1 is first env map
  1112. #define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
  1113. #define TEXTURE_CNT (ENV_CNT+13)
  1114.  
  1115. static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
  1116.  
  1117. void CL_RequestNextDownload (void)
  1118. {
  1119.     unsigned    map_checksum;        // for detecting cheater maps
  1120.     char fn[MAX_OSPATH];
  1121.     dmdl_t *pheader;
  1122.  
  1123.     if (cls.state != ca_connected)
  1124.         return;
  1125.  
  1126.     if (!allow_download->value && precache_check < ENV_CNT)
  1127.         precache_check = ENV_CNT;
  1128.  
  1129. //ZOID
  1130.     if (precache_check == CS_MODELS) { // confirm map
  1131.         precache_check = CS_MODELS+2; // 0 isn't used
  1132.         if (allow_download_maps->value)
  1133.             if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
  1134.                 return; // started a download
  1135.     }
  1136.     if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
  1137.         if (allow_download_models->value) {
  1138.             while (precache_check < CS_MODELS+MAX_MODELS &&
  1139.                 cl.configstrings[precache_check][0]) {
  1140.                 if (cl.configstrings[precache_check][0] == '*' ||
  1141.                     cl.configstrings[precache_check][0] == '#') {
  1142.                     precache_check++;
  1143.                     continue;
  1144.                 }
  1145.                 if (precache_model_skin == 0) {
  1146.                     if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
  1147.                         precache_model_skin = 1;
  1148.                         return; // started a download
  1149.                     }
  1150.                     precache_model_skin = 1;
  1151.                 }
  1152.  
  1153.                 // checking for skins in the model
  1154.                 if (!precache_model) {
  1155.  
  1156.                     FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
  1157.                     if (!precache_model) {
  1158.                         precache_model_skin = 0;
  1159.                         precache_check++;
  1160.                         continue; // couldn't load it
  1161.                     }
  1162.                     if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
  1163.                         // not an alias model
  1164.                         FS_FreeFile(precache_model);
  1165.                         precache_model = 0;
  1166.                         precache_model_skin = 0;
  1167.                         precache_check++;
  1168.                         continue;
  1169.                     }
  1170.                     pheader = (dmdl_t *)precache_model;
  1171.                     if (LittleLong (pheader->version) != ALIAS_VERSION) {
  1172.                         precache_check++;
  1173.                         precache_model_skin = 0;
  1174.                         continue; // couldn't load it
  1175.                     }
  1176.                 }
  1177.  
  1178.                 pheader = (dmdl_t *)precache_model;
  1179.  
  1180.                 while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
  1181.                     if (!CL_CheckOrDownloadFile((char *)precache_model +
  1182.                         LittleLong(pheader->ofs_skins) + 
  1183.                         (precache_model_skin - 1)*MAX_SKINNAME)) {
  1184.                         precache_model_skin++;
  1185.                         return; // started a download
  1186.                     }
  1187.                     precache_model_skin++;
  1188.                 }
  1189.                 if (precache_model) { 
  1190.                     FS_FreeFile(precache_model);
  1191.                     precache_model = 0;
  1192.                 }
  1193.                 precache_model_skin = 0;
  1194.                 precache_check++;
  1195.             }
  1196.         }
  1197.         precache_check = CS_SOUNDS;
  1198.     }
  1199.     if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) { 
  1200.         if (allow_download_sounds->value) {
  1201.             if (precache_check == CS_SOUNDS)
  1202.                 precache_check++; // zero is blank
  1203.             while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
  1204.                 cl.configstrings[precache_check][0]) {
  1205.                 if (cl.configstrings[precache_check][0] == '*') {
  1206.                     precache_check++;
  1207.                     continue;
  1208.                 }
  1209.                 Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
  1210.                 if (!CL_CheckOrDownloadFile(fn))
  1211.                     return; // started a download
  1212.             }
  1213.         }
  1214.         precache_check = CS_IMAGES;
  1215.     }
  1216.     if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
  1217.         if (precache_check == CS_IMAGES)
  1218.             precache_check++; // zero is blank
  1219.         while (precache_check < CS_IMAGES+MAX_IMAGES &&
  1220.             cl.configstrings[precache_check][0]) {
  1221.             Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
  1222.             if (!CL_CheckOrDownloadFile(fn))
  1223.                 return; // started a download
  1224.         }
  1225.         precache_check = CS_PLAYERSKINS;
  1226.     }
  1227.     // skins are special, since a player has three things to download:
  1228.     // model, weapon model and skin
  1229.     // so precache_check is now *3
  1230.     if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
  1231.         if (allow_download_players->value) {
  1232.             while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
  1233.                 int i, n;
  1234.                 char model[MAX_QPATH], skin[MAX_QPATH], *p;
  1235.  
  1236.                 i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
  1237.                 n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
  1238.  
  1239.                 if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
  1240.                     precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
  1241.                     continue;
  1242.                 }
  1243.  
  1244.                 if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
  1245.                     p++;
  1246.                 else
  1247.                     p = cl.configstrings[CS_PLAYERSKINS+i];
  1248.                 strcpy(model, p);
  1249.                 p = strchr(model, '/');
  1250.                 if (!p)
  1251.                     p = strchr(model, '\\');
  1252.                 if (p) {
  1253.                     *p++ = 0;
  1254.                     strcpy(skin, p);
  1255.                 } else
  1256.                     *skin = 0;
  1257.  
  1258.                 switch (n) {
  1259.                 case 0: // model
  1260.                     Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
  1261.                     if (!CL_CheckOrDownloadFile(fn)) {
  1262.                         precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
  1263.                         return; // started a download
  1264.                     }
  1265.                     n++;
  1266.                     /*FALL THROUGH*/
  1267.  
  1268.                 case 1: // weapon model
  1269.                     Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
  1270.                     if (!CL_CheckOrDownloadFile(fn)) {
  1271.                         precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
  1272.                         return; // started a download
  1273.                     }
  1274.                     n++;
  1275.                     /*FALL THROUGH*/
  1276.  
  1277.                 case 2: // weapon skin
  1278.                     Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
  1279.                     if (!CL_CheckOrDownloadFile(fn)) {
  1280.                         precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
  1281.                         return; // started a download
  1282.                     }
  1283.                     n++;
  1284.                     /*FALL THROUGH*/
  1285.  
  1286.                 case 3: // skin
  1287.                     Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
  1288.                     if (!CL_CheckOrDownloadFile(fn)) {
  1289.                         precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
  1290.                         return; // started a download
  1291.                     }
  1292.                     n++;
  1293.                     /*FALL THROUGH*/
  1294.  
  1295.                 case 4: // skin_i
  1296.                     Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
  1297.                     if (!CL_CheckOrDownloadFile(fn)) {
  1298.                         precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
  1299.                         return; // started a download
  1300.                     }
  1301.                     // move on to next model
  1302.                     precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
  1303.                 }
  1304.             }
  1305.         }
  1306.         // precache phase completed
  1307.         precache_check = ENV_CNT;
  1308.     }
  1309.  
  1310.     if (precache_check == ENV_CNT) {
  1311.         precache_check = ENV_CNT + 1;
  1312.  
  1313.         CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
  1314.  
  1315.         if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
  1316.             Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
  1317.                 map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
  1318.             return;
  1319.         }
  1320.     }
  1321.  
  1322.     if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
  1323.         if (allow_download->value && allow_download_maps->value) {
  1324.             while (precache_check < TEXTURE_CNT) {
  1325.                 int n = precache_check++ - ENV_CNT - 1;
  1326.  
  1327.                 if (n & 1)
  1328.                     Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx", 
  1329.                         cl.configstrings[CS_SKY], env_suf[n/2]);
  1330.                 else
  1331.                     Com_sprintf(fn, sizeof(fn), "env/%s%s.tga", 
  1332.                         cl.configstrings[CS_SKY], env_suf[n/2]);
  1333.                 if (!CL_CheckOrDownloadFile(fn))
  1334.                     return; // started a download
  1335.             }
  1336.         }
  1337.         precache_check = TEXTURE_CNT;
  1338.     }
  1339.  
  1340.     if (precache_check == TEXTURE_CNT) {
  1341.         precache_check = TEXTURE_CNT+1;
  1342.         precache_tex = 0;
  1343.     }
  1344.  
  1345.     // confirm existance of textures, download any that don't exist
  1346.     if (precache_check == TEXTURE_CNT+1) {
  1347.         // from qcommon/cmodel.c
  1348.         extern int            numtexinfo;
  1349.         extern mapsurface_t    map_surfaces[];
  1350.  
  1351.         if (allow_download->value && allow_download_maps->value) {
  1352.             while (precache_tex < numtexinfo) {
  1353.                 char fn[MAX_OSPATH];
  1354.  
  1355.                 sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
  1356.                 if (!CL_CheckOrDownloadFile(fn))
  1357.                     return; // started a download
  1358.             }
  1359.         }
  1360.         precache_check = TEXTURE_CNT+999;
  1361.     }
  1362.  
  1363. //ZOID
  1364.     CL_RegisterSounds ();
  1365.     CL_PrepRefresh ();
  1366.  
  1367.     MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  1368.     MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
  1369. }
  1370.  
  1371. /*
  1372. =================
  1373. CL_Precache_f
  1374.  
  1375. The server will send this command right
  1376. before allowing the client into the server
  1377. =================
  1378. */
  1379. void CL_Precache_f (void)
  1380. {
  1381.     //Yet another hack to let old demos work
  1382.     //the old precache sequence
  1383.     if (Cmd_Argc() < 2) {
  1384.         unsigned    map_checksum;        // for detecting cheater maps
  1385.  
  1386.         CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
  1387.         CL_RegisterSounds ();
  1388.         CL_PrepRefresh ();
  1389.         return;
  1390.     }
  1391.  
  1392.     precache_check = CS_MODELS;
  1393.     precache_spawncount = atoi(Cmd_Argv(1));
  1394.     precache_model = 0;
  1395.     precache_model_skin = 0;
  1396.  
  1397.     CL_RequestNextDownload();
  1398. }
  1399.  
  1400.  
  1401. /*
  1402. =================
  1403. CL_InitLocal
  1404. =================
  1405. */
  1406. void CL_InitLocal (void)
  1407. {
  1408.     cls.state = ca_disconnected;
  1409.     cls.realtime = Sys_Milliseconds ();
  1410.  
  1411.     CL_InitInput ();
  1412.  
  1413.     adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
  1414.     adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
  1415.     adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
  1416.     adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
  1417.     adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
  1418.     adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
  1419.     adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
  1420.     adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
  1421.     adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
  1422.  
  1423. //
  1424. // register our variables
  1425. //
  1426.     cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
  1427.     cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
  1428.  
  1429.     cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
  1430.     cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
  1431.     cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
  1432.     cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
  1433.     cl_gun = Cvar_Get ("cl_gun", "1", 0);
  1434.     cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
  1435.     cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
  1436.     cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
  1437.     cl_predict = Cvar_Get ("cl_predict", "1", 0);
  1438. //    cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
  1439.     cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
  1440.  
  1441.     cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
  1442.     cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
  1443.     cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
  1444.     cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
  1445.     cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
  1446.     cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
  1447.  
  1448.     cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
  1449.     freelook = Cvar_Get( "freelook", "0", CVAR_ARCHIVE );
  1450.     lookspring = Cvar_Get ("lookspring", "0", CVAR_ARCHIVE);
  1451.     lookstrafe = Cvar_Get ("lookstrafe", "0", CVAR_ARCHIVE);
  1452.     sensitivity = Cvar_Get ("sensitivity", "3", CVAR_ARCHIVE);
  1453.  
  1454.     m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE);
  1455.     m_yaw = Cvar_Get ("m_yaw", "0.022", 0);
  1456.     m_forward = Cvar_Get ("m_forward", "1", 0);
  1457.     m_side = Cvar_Get ("m_side", "1", 0);
  1458.  
  1459.     cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
  1460.     cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
  1461.     cl_showclamp = Cvar_Get ("showclamp", "0", 0);
  1462.     cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
  1463.     cl_paused = Cvar_Get ("paused", "0", 0);
  1464.     cl_timedemo = Cvar_Get ("timedemo", "0", 0);
  1465.  
  1466.     rcon_client_password = Cvar_Get ("rcon_password", "", 0);
  1467.     rcon_address = Cvar_Get ("rcon_address", "", 0);
  1468.  
  1469.     cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
  1470.  
  1471.     //
  1472.     // userinfo
  1473.     //
  1474.     info_password = Cvar_Get ("password", "", CVAR_USERINFO);
  1475.     info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
  1476.     name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
  1477.     skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
  1478.     rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE);    // FIXME
  1479.     msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
  1480.     hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
  1481.     fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
  1482.     gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
  1483.     gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
  1484.     gender->modified = false; // clear this so we know when user sets it manually
  1485.  
  1486.     cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
  1487.  
  1488.  
  1489.     //
  1490.     // register our commands
  1491.     //
  1492.     Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
  1493.     Cmd_AddCommand ("pause", CL_Pause_f);
  1494.     Cmd_AddCommand ("pingservers", CL_PingServers_f);
  1495.     Cmd_AddCommand ("skins", CL_Skins_f);
  1496.  
  1497.     Cmd_AddCommand ("userinfo", CL_Userinfo_f);
  1498.     Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
  1499.  
  1500.     Cmd_AddCommand ("changing", CL_Changing_f);
  1501.     Cmd_AddCommand ("disconnect", CL_Disconnect_f);
  1502.     Cmd_AddCommand ("record", CL_Record_f);
  1503.     Cmd_AddCommand ("stop", CL_Stop_f);
  1504.  
  1505.     Cmd_AddCommand ("quit", CL_Quit_f);
  1506.  
  1507.     Cmd_AddCommand ("connect", CL_Connect_f);
  1508.     Cmd_AddCommand ("reconnect", CL_Reconnect_f);
  1509.  
  1510.     Cmd_AddCommand ("rcon", CL_Rcon_f);
  1511.  
  1512. //     Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
  1513.  
  1514.     Cmd_AddCommand ("setenv", CL_Setenv_f );
  1515.  
  1516.     Cmd_AddCommand ("precache", CL_Precache_f);
  1517.  
  1518.     Cmd_AddCommand ("download", CL_Download_f);
  1519.  
  1520.     //
  1521.     // forward to server commands
  1522.     //
  1523.     // the only thing this does is allow command completion
  1524.     // to work -- all unknown commands are automatically
  1525.     // forwarded to the server
  1526.     Cmd_AddCommand ("wave", NULL);
  1527.     Cmd_AddCommand ("inven", NULL);
  1528.     Cmd_AddCommand ("kill", NULL);
  1529.     Cmd_AddCommand ("use", NULL);
  1530.     Cmd_AddCommand ("drop", NULL);
  1531.     Cmd_AddCommand ("say", NULL);
  1532.     Cmd_AddCommand ("say_team", NULL);
  1533.     Cmd_AddCommand ("info", NULL);
  1534.     Cmd_AddCommand ("prog", NULL);
  1535.     Cmd_AddCommand ("give", NULL);
  1536.     Cmd_AddCommand ("god", NULL);
  1537.     Cmd_AddCommand ("notarget", NULL);
  1538.     Cmd_AddCommand ("noclip", NULL);
  1539.     Cmd_AddCommand ("invuse", NULL);
  1540.     Cmd_AddCommand ("invprev", NULL);
  1541.     Cmd_AddCommand ("invnext", NULL);
  1542.     Cmd_AddCommand ("invdrop", NULL);
  1543.     Cmd_AddCommand ("weapnext", NULL);
  1544.     Cmd_AddCommand ("weapprev", NULL);
  1545. }
  1546.  
  1547.  
  1548.  
  1549. /*
  1550. ===============
  1551. CL_WriteConfiguration
  1552.  
  1553. Writes key bindings and archived cvars to config.cfg
  1554. ===============
  1555. */
  1556. void CL_WriteConfiguration (void)
  1557. {
  1558.     FILE    *f;
  1559.     char    path[MAX_QPATH];
  1560.  
  1561.     if (cls.state == ca_uninitialized)
  1562.         return;
  1563.  
  1564.     Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
  1565.     f = fopen (path, "w");
  1566.     if (!f)
  1567.     {
  1568.         Com_Printf ("Couldn't write config.cfg.\n");
  1569.         return;
  1570.     }
  1571.  
  1572.     fprintf (f, "// generated by quake, do not modify\n");
  1573.     Key_WriteBindings (f);
  1574.     fclose (f);
  1575.  
  1576.     Cvar_WriteVariables (path);
  1577. }
  1578.  
  1579.  
  1580. /*
  1581. ==================
  1582. CL_FixCvarCheats
  1583.  
  1584. ==================
  1585. */
  1586.  
  1587. typedef struct
  1588. {
  1589.     char    *name;
  1590.     char    *value;
  1591.     cvar_t    *var;
  1592. } cheatvar_t;
  1593.  
  1594. cheatvar_t    cheatvars[] = {
  1595.     {"timescale", "1"},
  1596.     {"timedemo", "0"},
  1597.     {"r_drawworld", "1"},
  1598.     {"cl_testlights", "0"},
  1599.     {"r_fullbright", "0"},
  1600.     {"r_drawflat", "0"},
  1601.     {"paused", "0"},
  1602.     {"fixedtime", "0"},
  1603.     {"sw_draworder", "0"},
  1604.     {"gl_lightmap", "0"},
  1605.     {"gl_saturatelighting", "0"},
  1606.     {NULL, NULL}
  1607. };
  1608.  
  1609. int        numcheatvars;
  1610.  
  1611. void CL_FixCvarCheats (void)
  1612. {
  1613.     int            i;
  1614.     cheatvar_t    *var;
  1615.  
  1616.     if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1") 
  1617.         || !cl.configstrings[CS_MAXCLIENTS][0] )
  1618.         return;        // single player can cheat
  1619.  
  1620.     // find all the cvars if we haven't done it yet
  1621.     if (!numcheatvars)
  1622.     {
  1623.         while (cheatvars[numcheatvars].name)
  1624.         {
  1625.             cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
  1626.                     cheatvars[numcheatvars].value, 0);
  1627.             numcheatvars++;
  1628.         }
  1629.     }
  1630.  
  1631.     // make sure they are all set to the proper values
  1632.     for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
  1633.     {
  1634.         if ( strcmp (var->var->string, var->value) )
  1635.         {
  1636.             Cvar_Set (var->name, var->value);
  1637.         }
  1638.     }
  1639. }
  1640.  
  1641. //============================================================================
  1642.  
  1643. /*
  1644. ==================
  1645. CL_SendCommand
  1646.  
  1647. ==================
  1648. */
  1649. void CL_SendCommand (void)
  1650. {
  1651.     // get new key events
  1652.     Sys_SendKeyEvents ();
  1653.  
  1654.     // allow mice or other external controllers to add commands
  1655.     IN_Commands ();
  1656.  
  1657.     // process console commands
  1658.     Cbuf_Execute ();
  1659.  
  1660.     // fix any cheating cvars
  1661.     CL_FixCvarCheats ();
  1662.  
  1663.     // send intentions now
  1664.     CL_SendCmd ();
  1665.  
  1666.     // resend a connection request if necessary
  1667.     CL_CheckForResend ();
  1668. }
  1669.  
  1670.  
  1671. /*
  1672. ==================
  1673. CL_Frame
  1674.  
  1675. ==================
  1676. */
  1677. void CL_Frame (int msec)
  1678. {
  1679.     static int    extratime;
  1680.     static int  lasttimecalled;
  1681.  
  1682.     if (dedicated->value)
  1683.         return;
  1684.  
  1685.     extratime += msec;
  1686.  
  1687.     if (!cl_timedemo->value)
  1688.     {
  1689.         if (cls.state == ca_connected && extratime < 100)
  1690.             return;            // don't flood packets out while connecting
  1691.         if (extratime < 1000/cl_maxfps->value)
  1692.             return;            // framerate is too high
  1693.     }
  1694.  
  1695.     // let the mouse activate or deactivate
  1696.     IN_Frame ();
  1697.  
  1698.     // decide the simulation time
  1699.     cls.frametime = extratime/1000.0;
  1700.     cl.time += extratime;
  1701.     cls.realtime = curtime;
  1702.  
  1703.     extratime = 0;
  1704. #if 0
  1705.     if (cls.frametime > (1.0 / cl_minfps->value))
  1706.         cls.frametime = (1.0 / cl_minfps->value);
  1707. #else
  1708.     if (cls.frametime > (1.0 / 5))
  1709.         cls.frametime = (1.0 / 5);
  1710. #endif
  1711.  
  1712.     // if in the debugger last frame, don't timeout
  1713.     if (msec > 5000)
  1714.         cls.netchan.last_received = Sys_Milliseconds ();
  1715.  
  1716.     // fetch results from server
  1717.     CL_ReadPackets ();
  1718.  
  1719.     // send a new command message to the server
  1720.     CL_SendCommand ();
  1721.  
  1722.     // predict all unacknowledged movements
  1723.     CL_PredictMovement ();
  1724.  
  1725.     // allow rendering DLL change
  1726.     VID_CheckChanges ();
  1727.     if (!cl.refresh_prepped && cls.state == ca_active)
  1728.         CL_PrepRefresh ();
  1729.  
  1730.     // update the screen
  1731.     if (host_speeds->value)
  1732.         time_before_ref = Sys_Milliseconds ();
  1733.     SCR_UpdateScreen ();
  1734.     if (host_speeds->value)
  1735.         time_after_ref = Sys_Milliseconds ();
  1736.  
  1737.     // update audio
  1738.     S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
  1739.     
  1740.     CDAudio_Update();
  1741.  
  1742.     // advance local effects for next frame
  1743.     CL_RunDLights ();
  1744.     CL_RunLightStyles ();
  1745.     SCR_RunCinematic ();
  1746.     SCR_RunConsole ();
  1747.  
  1748.     cls.framecount++;
  1749.  
  1750.     if ( log_stats->value )
  1751.     {
  1752.         if ( cls.state == ca_active )
  1753.         {
  1754.             if ( !lasttimecalled )
  1755.             {
  1756.                 lasttimecalled = Sys_Milliseconds();
  1757.                 if ( log_stats_file )
  1758.                     fprintf( log_stats_file, "0\n" );
  1759.             }
  1760.             else
  1761.             {
  1762.                 int now = Sys_Milliseconds();
  1763.  
  1764.                 if ( log_stats_file )
  1765.                     fprintf( log_stats_file, "%d\n", now - lasttimecalled );
  1766.                 lasttimecalled = now;
  1767.             }
  1768.         }
  1769.     }
  1770. }
  1771.  
  1772.  
  1773. //============================================================================
  1774.  
  1775. /*
  1776. ====================
  1777. CL_Init
  1778. ====================
  1779. */
  1780. void CL_Init (void)
  1781. {
  1782.     if (dedicated->value)
  1783.         return;        // nothing running on the client
  1784.  
  1785.     // all archived variables will now be loaded
  1786.  
  1787.     Con_Init ();    
  1788. #if defined __linux__ || defined __sgi
  1789.     S_Init ();    
  1790.     VID_Init ();
  1791. #else
  1792.     VID_Init ();
  1793.     S_Init ();    // sound must be initialized after window is created
  1794. #endif
  1795.     
  1796.     V_Init ();
  1797.     
  1798.     net_message.data = net_message_buffer;
  1799.     net_message.maxsize = sizeof(net_message_buffer);
  1800.  
  1801.     M_Init ();    
  1802.     
  1803.     SCR_Init ();
  1804.     cls.disable_screen = true;    // don't draw yet
  1805.  
  1806.     CDAudio_Init ();
  1807.     CL_InitLocal ();
  1808.     IN_Init ();
  1809.  
  1810. //    Cbuf_AddText ("exec autoexec.cfg\n");
  1811.     FS_ExecAutoexec ();
  1812.     Cbuf_Execute ();
  1813.  
  1814. }
  1815.  
  1816.  
  1817. /*
  1818. ===============
  1819. CL_Shutdown
  1820.  
  1821. FIXME: this is a callback from Sys_Quit and Com_Error.  It would be better
  1822. to run quit through here before the final handoff to the sys code.
  1823. ===============
  1824. */
  1825. void CL_Shutdown(void)
  1826. {
  1827.     static qboolean isdown = false;
  1828.     
  1829.     if (isdown)
  1830.     {
  1831.         printf ("recursive shutdown\n");
  1832.         return;
  1833.     }
  1834.     isdown = true;
  1835.  
  1836.     CL_WriteConfiguration (); 
  1837.  
  1838.     CDAudio_Shutdown ();
  1839.     S_Shutdown();
  1840.     IN_Shutdown ();
  1841.     VID_Shutdown();
  1842. }
  1843.  
  1844.  
  1845.